package Game;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferStrategy;


@SuppressWarnings("serial")
/**
 * extends Canvas
 * implements Runnalbe to have a runnalbe game
 * implements keylistener to interact with the invirament
 * @author DevBo
 */
public abstract class GameCanvas extends Canvas implements Runnable,KeyListener{
 public static final long ONE_SECOND_MILI = 1000;
 protected int frameW;
 protected int frameH;
 /** frames per second */
 protected long fps;
 //TODO explain period
 /** the amount of time */
 private long period = 15;
 private BufferStrategy buff;
 private Graphics graph;
 private Color bckGround=(Color.LIGHT_GRAY);
 private Image bckGround_img;
 private Thread t;
 /** is left arrow key pressed */
 public static boolean left;
 /** is right arrow key pressed */
 public static boolean right;
 /** is up arrow key pressed */
 public static boolean up;
 /** is down arrow key pressed */
 public static boolean down;
 /** is q key pressed */
 public static boolean q;
 /** is space bar pressed */
 public static boolean spaceBar;
 /** if A is pressed*/
 public static boolean a;
 /** if D is Pressed*/
 public static boolean d;
 /** the last pressed arrow key of the X axis
  * left = 1
  * right = 2
  */
 public static int lastpressedx=1;
 /** the second to last pressed arrow key of the Y axis
  * left = 1
  * right = 2
  */
 public static int newlastpressedx;
 /** the last pressed arrow key of the Y axis
  * up = 1
  * down = 2
  */
 public static int lastpressedy=2;
 /** the second to last pressed arrow key of the Y axis
  * up = 1
  * down = 2
  */
 public static int newlastpressedy;
 /** the last pressed arrow key axis
  * X axis = 1
  * Y axis = 2
  */
 public static int lastpressedxy=2;
 /** the value of FPS to display on screen */
 private String drawFps = "0";
 	/**
 	 * constructor
 	 * @param w Width of frame
 	 * @param h Height of frame
 	 */
 	public GameCanvas(int w,int h){
 		this.frameW=w;
 		this.frameH=h;
		this.setIgnoreRepaint(true);
		this.setBounds(0,0,frameW,frameH);
		this.setBackground(Color.GREEN);
		this.setVisible(true);
 	}
 	/**
 	 * constructor
 	 * @param w Width of frame
 	 * @param h Height of frame
 	 * @param color Color for the backgroud
 	 */
 	public GameCanvas(int w,int h,Color color){
 		this.frameW=w;
 		this.frameH=h;
 		this.bckGround=color;
		this.setIgnoreRepaint(true);
		this.setBounds(0,0,frameW,frameH);
		this.setBackground(bckGround);
		this.setVisible(true);
 	}
 	//TODO expain this
 	public void addNotify(){
		super.addNotify();
		this.createBufferStrategy(2);
		this.buff=this.getBufferStrategy();
		requestFocus();
		startGame();
	}
 	/** start thread for game */
 	public void startGame(){
		if (t==null){
			t=new Thread(this);
			t.start();
		}
	}
	public void run(){
		while(true){
			long beginTime=System.currentTimeMillis();
			Update();
			Render();
			Draw();
			fps=System.currentTimeMillis() - beginTime ;
			long sleepTime=period-fps;
			if (sleepTime == 30) sleepTime = -1;
			fps= ONE_SECOND_MILI / ((period * 2) - sleepTime);
			try{
				if (sleepTime > 0){
					Thread.sleep(sleepTime);
					
				}
			}
			catch(Exception e){
			}
		}
	}
	public void Render(){
		graph = buff.getDrawGraphics();
		
		if (!HasImgBackground()){
			graph.setColor(bckGround);
			graph.fillRect(0, 0, frameW, frameH);
		}else{
			graph.drawImage(bckGround_img, 0, 0, frameW, frameH,null);
		}
		graph.setColor(new Color(255,255,255));
		graph.drawString("FPS: " + fps , 10, 15);
		Paint(graph);
	}
	private void Draw(){
		if(!buff.contentsLost()){
			buff.show();
			if(graph != null){
				graph.dispose();
			}
		}
	}
	private boolean HasImgBackground(){
		if (bckGround_img==null){
			return false;
		}
		return true;
	}
	public void setBackgroundImg(Image image){
		this.bckGround_img=image;
	}
	public void deleteBackground(){
		this.bckGround_img=null;
	}
	public void keyPressed(KeyEvent e) {
		if(e.getKeyCode()==KeyEvent.VK_W){
			spaceBar=true;
		}
		if(e.getKeyCode()==KeyEvent.VK_LEFT){
			left=true;
			if(lastpressedx!=1)
				newlastpressedx=lastpressedx;
			lastpressedx=1;
			lastpressedxy=1;
		}
		if(e.getKeyCode()==KeyEvent.VK_UP){
			up=true;
			if(lastpressedy!=1)
				newlastpressedy=lastpressedy;
			lastpressedy=1;
			lastpressedxy=2;
		}
		if(e.getKeyCode()==KeyEvent.VK_RIGHT){
			right=true;
			if(lastpressedx!=2)
				newlastpressedx=lastpressedx;
			lastpressedx=2;
			lastpressedxy=1;
		}
		if(e.getKeyCode()==KeyEvent.VK_DOWN){
			down=true;
			if(lastpressedy!=2)
				newlastpressedy=lastpressedy;
			lastpressedy=2;
			lastpressedxy=2;
		}
		if(e.getKeyCode()==KeyEvent.VK_Q){
			q=true;
		}
		if(e.getKeyCode()==KeyEvent.VK_A){
			a=true;
		}
		if(e.getKeyCode()==KeyEvent.VK_D){
			d=true;
		}
	}
	
	public void keyReleased(KeyEvent e) {
		if(e.getKeyCode()==KeyEvent.VK_W){
			spaceBar=false;
		}
		if(e.getKeyCode()==KeyEvent.VK_LEFT){
			left=false;
			if(right)
				if(newlastpressedx!=0)
				lastpressedx=newlastpressedx;
			if(!right){
				if(up||down){
					lastpressedxy=2;
				}
			}
		}
		if(e.getKeyCode()==KeyEvent.VK_UP){
			up=false;
			if(down)
				if(newlastpressedy!=0)
				lastpressedy=newlastpressedy;
			if(!down){
				if(left||right){
					lastpressedxy=1;
				}
			}
		}
		if(e.getKeyCode()==KeyEvent.VK_RIGHT){
			right=false;
			if(left)
				if(newlastpressedx!=0)
				lastpressedx=newlastpressedx;
			if(!left){
				if(up||down){
					lastpressedxy=2;
				}
			}
		}
		if(e.getKeyCode()==KeyEvent.VK_DOWN){
			down=false;
			if(up)
				if(newlastpressedy!=0)
				lastpressedy=newlastpressedy;
			if(!up){
				if(left||right){
					lastpressedxy=1;
				}
			}
		}
		if(e.getKeyCode()==KeyEvent.VK_Q){
			q=false;
		}
		if(e.getKeyCode()==KeyEvent.VK_A){
			a=false;
		}
		if(e.getKeyCode()==KeyEvent.VK_D){
			d=false;
		}
	}
	public void keyTyped(KeyEvent e) {
	}
	public boolean getA(){
		return a;
	}
	public boolean getD(){
		return d;
	}
	abstract void Update();
	abstract void Paint(Graphics g);
}
